﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using MiUi.ShuaMiHelper;
using System.Net;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
using MSScriptControl;
using System.IO;
using System.Threading;

namespace MiUi.ShuaMi
{
    public partial class FrmShuaMi : Form
    {
        public FrmShuaMi()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 用户
        /// </summary>
        private MiUiUser miuiUser;
        /// <summary>
        /// 地址
        /// </summary>
        private OperatingUrl operatingUrl;
        /// <summary>
        /// 请求
        /// </summary>
        private HttpClient httpClient;
        private Encoding encoding = Encoding.UTF8;
        /// <summary>
        /// 回复的post地址
        /// </summary>
        private string replyPostUrl;

        /// <summary>
        /// keyValue 回复时,提交使用
        /// </summary>
        private IList<KeyValue> replyList;

        private ValidateVersion vv;

        private int seqNum=0;

        /// <summary>
        /// 是否停止
        /// </summary>
        private bool IsStop = false;

        private void FrmShuaMi_Load(object sender, EventArgs e)
        {
            this.miuiUser = new MiUiUser(); 
            this.operatingUrl = new OperatingUrl();
            
            //登陆地址，和提交地址是相同的
            this.operatingUrl.AdressLogin = "http://passport.xiaomi.com/index.php?goto=http://bbs.xiaomi.com/extra.php?mod=xiaomi/authcallback";
            this.operatingUrl.AdressLoginSubmit = "http://passport.xiaomi.com/index.php?goto=http://bbs.xiaomi.com/extra.php?mod=xiaomi/authcallback";
            this.operatingUrl.AdressGetRewardPoints = "http://bbs.xiaomi.com/home-spacecp-ac-credit.html";
            this.tbReplyContent.Text = "支持小米！！~~~~~~~~~";
            //this.tbNumCheckResult.te
            httpClient = new HttpClient(new Uri("http://www.xiaomi.com"));
            vv = new ValidateVersion();
            vv.beginDateTime = Convert.ToDateTime("2011-09-23");
            vv.Days = 1;
                
        }

        // 工具-> 选项 单击事件
        private void tsmiSet_Click(object sender, EventArgs e)
        {
            FrmSet frmSet = new FrmSet();
            frmSet.eventSetMiUiUser += new Action<MiUiUser>(frmSet_eventMiUiUser);
            frmSet.Show();
        }

        //设置用户信息
        void frmSet_eventMiUiUser(MiUiUser user)
        {
            miuiUser.UserName = user.UserName;
            miuiUser.Password = user.Password;
            miuiUser.ThreadStartId = user.ThreadStartId;
        }

        //LoginForm%5Busername%5D=feiazifeiazi@163.com&LoginForm%5Bpassword%5D=qsiofg4nui&LoginForm%5BrememberMe%5D=0&LoginForm%5BrememberMe%5D=1&yt0=%E7%99%BB%E5%BD%95
        private void btnStart_Click(object sender, EventArgs e)
        {
            int b= vv.Validate();
            if (b==0)
            {
                MessageBox.Show("网络异常..");
                return;
            }else if (b!=1)
            {
                MessageBox.Show("已过期..请联系作者. QQ:404313364");
                return;
            }

            IList<KeyValue> list = new List<KeyValue>();
            list.Add(new KeyValue() { Key = Helpers.StrConvUrlEncoding("LoginForm[username]", encoding), Value = this.miuiUser.UserName });
            list.Add(new KeyValue() { Key = Helpers.StrConvUrlEncoding("LoginForm[password]", encoding), Value = this.miuiUser.Password });
            list.Add(new KeyValue() { Key = Helpers.StrConvUrlEncoding("LoginForm[rememberMe]", encoding), Value = "0" });
            list.Add(new KeyValue() { Key = Helpers.StrConvUrlEncoding("LoginForm[rememberMe]", encoding), Value = "1" });
            list.Add(new KeyValue() { Key = Helpers.StrConvUrlEncoding("yt0", encoding), Value = Helpers.StrConvUrlEncoding("登录", encoding) });

            PostData postData = new PostData();
            string postString = postData.ToString(list);
            
            httpClient.Headers.Add("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; GTB6.5; QQDownload 680; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; .NET CLR 1.1.4322)");
            httpClient.Headers.Add("Accept-Encoding", "deflate");
            //byte[] responseData = httpClient.DownloadData(this.operatingUrl.AdressLogin);
            //string srcString = encoding.GetString(responseData);
            string responseHtml = httpClient.PostData(this.operatingUrl.AdressLoginSubmit, postString, encoding, encoding);
            if (responseHtml.Contains("<a href=\"http://bbs.xiaomi.com/home-spacecp.html\">个人中心</a></span><span class=\"pipe\">|</span>"))
            {
                this.SetText("登陆成功");
                string rewardPoint=GetRewardPoints();
                this.SetText(rewardPoint);
            }
            else if (responseHtml.Contains("<span class=\"hidden\">密码输入不正确！</span>"))
            {
                this.SetText("用户名或密码错误! 工具->选项 进行设置");
            }
            else
            {
                this.SetText(responseHtml);
            }
        }


        
        private void btnReply_Click(object sender, EventArgs e)
        {
            InitReplyThread(true);
        }

        /// <summary>
        /// //获取 idhash,验证码等
        /// </summary>
        /// <param name="isLoadCheck">是否加载验证码</param>
        private void InitReplyThread(bool isLoadCheck)
        {
            string adressReply = "http://bbs.xiaomi.com/thread-" + (miuiUser.ThreadStartId++) + "-1-150.html";
            string idHash = GetIdHash(adressReply);
            if (isLoadCheck)
            {
                string secqaa = UpdateSecqaa(idHash, adressReply);
            object obj = this.ExecJs(secqaa);
            SetTbNumCheck(secqaa);
            SetTbNumCheckResult(obj == null ? "" : obj.ToString());

            string seccodeUlr = UpdateSeccode(idHash, adressReply);
            LoadSeCodeImage("http://bbs.xiaomi.com/" + seccodeUlr, adressReply);
            }
            
        }

        //计算的 表达式
        private void SetTbNumCheck(string secqaa)
        {
            if (this.tbNumCheck.InvokeRequired)
            {
                Action<string> set = new Action<string>(SetTbNumCheck);
                this.Invoke(set, secqaa);
            }
            else
            {
                this.tbNumCheck.Text = secqaa;
            }
        }

        //计算的 表达式
        private void SetTbNumCheckResult(string result)
        {
            if (this.tbNumCheckResult.InvokeRequired)
            {
                Action<string> set = new Action<string>(SetTbNumCheckResult);
                this.Invoke(set, result);
            }
            else
            {
                this.tbNumCheckResult.Text = result;

            }
        }





        //数字运算 验证码
        //http://bbs.xiaomi.com/misc.php?mod=secqaa&action=check&inajax=1&&idhash=SalPz&secverify=46
        //图形验证码
        //http://bbs.xiaomi.com/misc.php?mod=seccode&action=check&inajax=1&&idhash=SalPz&secverify=vr98
        // 正确 返回结果(2种 验证)
        //<?xml version="1.0" encoding="utf-8"?><root><![CDATA[succeed]]></root>
        // 错误 返回结果(2种 验证)
        //<?xml version="1.0" encoding="utf-8"?><root><![CDATA[invalid]]></root>

        //<span id="secqaa_SI4Jj"></span>
        //<span id="seccode_SI4Jj"></span>

        //<?xml version="1.0" encoding="utf-8"?>
        //<root><![CDATA[<script type="text/javascript" reload="1">if($('return_fastpost')) $('return_fastpost').className='onerror';if(typeof succeedhandle_fastpost=='function') {succeedhandle_fastpost('forum.php?mod=viewthread&tid=290517&pid=9033296&page=2&extra=page%3D189800#pid9033296', '非常感谢，你的回复已经发布，现在将转入主题页。[ 需要转入主题列表请点击这里 ]', {'fid':'11','tid':'290517','pid':'9033296','from':'','sechash':'SHKM5'});}</script>]]></root>


        //验证问答的答案填写错误，请返回修改
        //验证码填写错误，请返回修改
        //对不起，您两次发表间隔少于
        //对不起，本主题已关闭，不再接受新回复，请返回
        //>对不起，你的帖子小于 26 个字符的限制，请返回修改
        /// <summary>
        /// 回复贴子
        /// </summary>
        /// <returns></returns>
        private void Reply()
        {

            Thread thread = new Thread(new ThreadStart(BeginReply));
            thread.Start();
           
        }

        private void BeginReply()
        {
            this.IsStop = false;
            bool bResult = true;
            while (!this.IsStop && bResult)
            {
                //string adressSecqaa = "http://bbs.xiaomi.com/misc.php?mod=secqaa&action=check&inajax=1&&idhash={0}&secverify={1}";
                //string adressSeccode = "http://bbs.xiaomi.com/misc.php?mod=seccode&action=check&inajax=1&&idhash={0}&secverify={2}";
                //message=%E6%94%AF%E6%8C%81%E5%B0%8F%E7%B1%B3%EF%BC%81%EF%BC%81%7E%7E%7E%7E%7E%7E%7E%7E%7E&
                //sechash=SHKM5&
                //secanswer=33&
                //seccodeverify=4feq&
                //formhash=cdf4d2b6&
                //subject=
                try
                {
                    if (replyList == null)
                    {
                        bResult = false;
                        return;
                    }
                    IList<KeyValue> replyKeyValueList = new List<KeyValue>();
                    replyKeyValueList.Add(new KeyValue() { Key = "message", Value = Helpers.StrConvUrlEncoding(this.tbReplyContent.Text, encoding) });
                    //replyKeyValueList.Add(new KeyValue() { Key = "sechash", Value = replyList.FirstOrDefault(v => v.Key == "sechash").Value });
                    //replyKeyValueList.Add(new KeyValue() { Key = "secanswer", Value = this.tbNumCheckResult.Text });
                    //replyKeyValueList.Add(new KeyValue() { Key = "seccodeverify", Value = this.txtCode.Text.Trim() });
                    replyKeyValueList.Add(new KeyValue() { Key = "formhash", Value = replyList.FirstOrDefault(v => v.Key == "formhash").Value });
                    replyKeyValueList.Add(new KeyValue() { Key = "subject", Value = replyList.FirstOrDefault(v => v.Key == "subject").Value });
                    int tid = miuiUser.ThreadStartId++;
                    this.replyPostUrl = Regex.Replace(this.replyPostUrl, "tid=(.|\n)*?&", "tid=" + tid + "&");
                    this.SetText("帖子地址:" + "http://bbs.xiaomi.com/thread-" + tid + "-1-150.html");
                    string postUrl = "http://bbs.xiaomi.com/" + this.replyPostUrl.Replace("&amp;", "&");
                    //replyList.Remove(keyValue);
                    PostData postData = new PostData();

                    httpClient.Headers.Add("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; GTB6.5; QQDownload 680; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; .NET CLR 1.1.4322)");
                    httpClient.Headers.Add("Referer", "http://bbs.xiaomi.com");


                    string resoponseHtml = httpClient.PostData(postUrl, postData.ToString(replyKeyValueList), encoding, encoding);
                    if (resoponseHtml.Contains("验证问答的答案填写错误，请返回修改"))
                    {
                        this.SetText("验证问答的答案填写错误！");
                        bResult = false;

                    }
                    else if (resoponseHtml.Contains("验证码填写错误，请返回修改"))
                    {
                        this.SetText("验证码填写错误，请返回修改");
                        bResult = false;

                    }
                    else if (resoponseHtml.Contains("对不起，你的帖子小于 26 个字符的限制，请返回修改"))
                    {
                        this.SetText("对不起，你的帖子小于 26 个字符的限制，请返回修改");
                        bResult = false;
                    }
                    else
                    {

                        if (resoponseHtml.Contains("对不起，您两次发表间隔少于"))
                        {
                            this.SetText("对不起，您两次发表间隔少于82秒。。");
                            --miuiUser.ThreadStartId;
                            this.SetTextNotOther(string.Format("{0}{1} {2}", "", DateTime.Now, "程序睡觉83秒."));

                            for (int i = 0; i < 8; i++)
                            {
                                Thread.Sleep(10 * 1000);
                                this.SetTextNotOther(".");
                            }
                            Thread.Sleep(3 * 1000);
                            this.SetTextNotOther(Environment.NewLine);

                        }
                        else if (resoponseHtml.Contains("对不起，本主题已关闭，不再接受新回复，请返回"))
                        {
                            this.SetText("对不起，本主题已关闭，不再接受新回复，请返回..");
                        }
                        else if (resoponseHtml.Contains("对不起，您所在的用户组每小时限制发帖"))
                        {
                            this.SetText("对不起，您所在的用户组每小时限制发帖 XX 个，请稍后再发表/");
                            this.IsStop = true;
                            this.SetText("程序停止了..");
                        }
                        string rewardPoint = GetRewardPoints();
                        this.SetText(rewardPoint);
                        //InitReplyThread(false);
                        bResult = true;
                    }
                }
                catch (Exception e)
                {
                    this.SetText("异常:"+e.Message);
                }
            }
        }

        /// <summary>
        /// 在页面，获取 idHash值,formhash值，post地址
        /// </summary>
        /// <returns></returns>
        private string GetIdHash(string adressReply)
        {
            string result = string.Empty;
            httpClient.Headers.Add("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; GTB6.5; QQDownload 680; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; .NET CLR 1.1.4322)");
            byte[] responseData = httpClient.DownloadData(adressReply);
            string srcString = encoding.GetString(responseData);

            MatchData matchData2 = new MatchData("<title>", "</title>", srcString);
            matchData2.Match();
            matchData2.Substring();
            this.SetText("回复贴子地址:" + adressReply + " 标题:" + matchData2.Result);

            MatchData matchData = new MatchData("","", srcString);

            matchData.StartStr = "id=\"fastpostform\" action=\"";
            matchData.EndStr = "\" onSubmit";//=\"return fastpostvalidate(this)\">
            matchData.Match(); matchData.Substring();
            this.replyPostUrl = matchData.Result;

            matchData.StartStr = "<span id=\"secqaa_";
            matchData.EndStr =  "\"></span>";
            matchData.Match();
            matchData.Substring();
            string sechash = matchData.Result;

            matchData.StartStr = "<input type=\"hidden\" name=\"formhash\" value=\"";
            matchData.EndStr = "\" />";
            matchData.Match(); matchData.Substring();
            string formhash = matchData.Result;

            matchData.StartStr = "<input type=\"hidden\" name=\"subject\" value=\"";
            matchData.EndStr = "\" />";
            matchData.Match(); matchData.Substring();
            string subject = matchData.Result;

            replyList = new List<KeyValue>();
            replyList.Add(new KeyValue() { Key = "sechash", Value = sechash });
            replyList.Add(new KeyValue() { Key = "formhash", Value = formhash });
            replyList.Add(new KeyValue() { Key = "subject", Value = subject });

            return sechash;
        }
       
        //请求地址
        //http://bbs.xiaomi.com/misc.php?mod=secqaa&action=update&idhash=ShE9K&inajax=1&ajaxtarget=secqaa_ShE9K
        //返回内容
        // <?xml version="1.0" encoding="utf-8"?>
        //<root><![CDATA[输入下面问题的答案<br />47 + 5 = ?]]></root>

       /// <summary>
        /// 更新 数字运算验证码
       /// </summary>
       /// <param name="idHash"></param>
       /// <returns></returns>
        private string UpdateSecqaa(string idHash, string adressReply)
        {
            string adressSeccode = 
                string.Format("http://bbs.xiaomi.com/misc.php?mod=secqaa&action=update&idhash={0}&inajax=1&ajaxtarget=secqaa_{0}",idHash);
            string result = string.Empty;
            httpClient.Headers.Add("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; GTB6.5; QQDownload 680; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; .NET CLR 1.1.4322)");
            httpClient.Headers.Add("x-requested-with", "XMLHttpRequest");
            httpClient.Headers.Add("Referer", adressReply);
        
            byte[] responseData = httpClient.DownloadData(adressSeccode);
            string srcString = encoding.GetString(responseData);
            MatchData matchData = new MatchData("输入下面问题的答案<br />", "= \\?]]>", srcString);
            matchData.Match();
            matchData.Substring();
            return matchData.Result;
        }



        //请求地址
        //http://bbs.xiaomi.com/misc.php?mod=seccode&action=update&idhash=ShE9K&inajax=1&ajaxtarget=seccode_ShE9K
        //返回内容
        //<?xml version="1.0" encoding="utf-8"?>
        //<root><![CDATA[输入下图中的字符<br /><img onclick="updateseccode('ShE9K')" width="150" height="60" src="misc.php?mod=seccode&update=32744&idhash=ShE9K" class="vm" alt="" />]]></root>

        /// <summary>
        /// 更新 图形 验证码
       /// </summary>
       /// <param name="idHash"></param>
       /// <returns></returns>
        private string UpdateSeccode(string idHash, string adressReply)
        {
            string adressSeccode = 
                string.Format("http://bbs.xiaomi.com/misc.php?mod=seccode&action=update&idhash={0}&inajax=1&ajaxtarget=seccode_ShE9K", idHash);
            string result = string.Empty;
            httpClient.Headers.Add("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; GTB6.5; QQDownload 680; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; .NET CLR 1.1.4322)");
            httpClient.Headers.Add("Referer", adressReply);

            byte[] responseData = httpClient.DownloadData(adressSeccode);
            string srcString = encoding.GetString(responseData);
            MatchData matchData = new MatchData("src=\"","\" class=\"vm\"", srcString);
            matchData.Match();
            matchData.Substring();
            return matchData.Result;
        }

        /// <summary>
        /// 加载验证码图片
        /// </summary>
        private void LoadSeCodeImage(string adressImage, string adressReply)
        {
            httpClient.Headers.Add("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; GTB6.5; QQDownload 680; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; .NET CLR 1.1.4322)");
            httpClient.Headers.Add("Referer", adressReply);
            httpClient.DownloadDataAsync(new Uri(adressImage), adressReply);

            httpClient.DownloadDataCompleted += new DownloadDataCompletedEventHandler(httpClient_DownloadDataCompleted);
        }

        void httpClient_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
        {
            try
            {
                this.pbCheckImage.Image = Image.FromStream(new MemoryStream(e.Result));
            }
            catch (Exception)
            {
                this.SetText("加载验证码，失败.");
            }

        }


        /// <summary>
        /// 执行JS
        /// </summary>
        /// <returns></returns>
        private object ExecJs(string evalContent)
        {
            ScriptControlClass scc = new ScriptControlClass();
            scc.Language = "javascript";
            object o = scc.Eval(evalContent);
            return o;
        }


        /// <summary>
        /// 获取积分
        /// </summary>
        /// <returns></returns>
        private string GetRewardPoints()
        {
            string result = string.Empty;
            httpClient.Headers.Add("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; GTB6.5; QQDownload 680; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; .NET CLR 1.1.4322)");
            
            byte[] responseData = httpClient.DownloadData(this.operatingUrl.AdressGetRewardPoints);
            string srcString = encoding.GetString(responseData);
            MatchData matchData = new MatchData("<table cellspacing=\"0\" cellpadding=\"0\" class=\"tfm bbda\">", "</table>", srcString);
            matchData.Match();
            matchData.Substring();
            if (!string.IsNullOrEmpty(matchData.Result))
            {

                string temp = Regex.Replace(matchData.Result, "<[^>]*>", "").
                    Replace(Environment.NewLine, "").
                    Replace("米", "米" + Environment.NewLine);
                
                result = "我的积分:" + Environment.NewLine + temp;

            }
            else
            {
                result = "我的积分:"+Environment.NewLine+"未获取到相关的积分信息.";
            }
            return result;
        }




        //给值
        /// <summary>
        ///  给值
        /// </summary>
        /// <param name="text"></param>
        private void SetText(string text)
        {
            if (this.rtbResult.InvokeRequired)
            {
                Action<string> set = new Action<string>(SetText);
                this.Invoke(set, text);
            }
            else
            {
                this.rtbResult.AppendText(string.Format("{0}.\t{1}\t{2}{3}", ++seqNum, DateTime.Now, text, Environment.NewLine));
                if (seqNum%100==0)
                {
                    VoteLog.AddResult("MIUI.mi",this.rtbResult.Text);
                    this.rtbResult.Clear();
                }
                this.rtbResult.ScrollToCaret();

            }
        }

        //给值
        /// <summary>
        ///  给值
        /// </summary>
        /// <param name="text"></param>
        private void SetTextNotOther(string text)
        {
            if (this.rtbResult.InvokeRequired)
            {
                Action<string> set = new Action<string>(SetTextNotOther);
                this.Invoke(set, text);
            }
            else
            {
                this.rtbResult.AppendText(text);
                this.rtbResult.ScrollToCaret();

            }
        }

        private void txtCode_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode== Keys.Enter)
            {
                Reply();
            }
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.IsStop = true;
        }


        

    }
}
